package com.fc.nacosdemo.listener;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 主动监听nacos配置 类
 * @param <T>
 */
public abstract class NacosAbstractListener<T> implements InitializingBean, Listener {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    protected final String clazzSimpleName = getClass().getSimpleName();


    protected T data;

    public T getData() {
        return data;
    }

    /**
     * bean初始化 触发 执行
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        ConfigService configService = this.getConfigService();
        try {
            String config = configService.getConfig(getDataId(), getGroupId(), getTimeout());
            logger.info("{}#afterPropertiesSet init configInfo. configInfo={}", clazzSimpleName, config);
            compile(config);
            configService.addListener(getDataId(), getGroupId(), this);
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            2, 4, 1, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    /**
     * 监听-工作线程池
     * @return
     */
    @Override
    public Executor getExecutor() {
        return threadPoolExecutor;
    }

    /**
     * 接受到Nacos 具体 配置信息变动
     *
     * @param configInfo
     */
    @Override
    public void receiveConfigInfo(String configInfo) {
        logger.info("{}#receiveConfigInfo receive configInfo. configInfo={}", clazzSimpleName, configInfo);
        compile(configInfo);
    }

    /**
     * 获取nacos dataId
     *
     * @return nacos dataId
     */
    protected abstract String getDataId();

    /**
     * 获取nacos groupId
     * <p>默认NacosConstant.GROUP_ID</p>
     *
     * @return nacos groupId
     */
    protected abstract String getGroupId();

    protected abstract String getNameSpace();

    /**
     * 获取nacos 超时时间
     * <p>默认NacosConstant.TIMEOUT</p>
     *
     * @return nacos 超时时间
     */
    protected long getTimeout() {
        return 3000L;
    }

    /**
     * 将输入转为数据
     *
     * @param dataStr
     */
    protected abstract void compile(String dataStr);

    /**
     * 获取ConfigService
     *
     * @return
     */
    private ConfigService getConfigService() {
        String serverAddr = getServerAddr();
        String nameSpace = this.getNameSpace();
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, nameSpace);
        ConfigService configService;
        try {
            configService = NacosFactory.createConfigService(properties);
        } catch (NacosException e) {
            e.printStackTrace();
            throw new RuntimeException("Nacos config 配置 异常");
        }
        return configService;
    }

    /**
     * 获取server addr
     *
     * @return
     */
    protected abstract String getServerAddr();

}
